home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / applications / wp / xvi.lha / Xvi_V1.0_Src / windows.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-04  |  9.3 KB  |  470 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)windows.c    2.2 (Chris & John Downey) 8/28/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     windows.c
  14. * module function:
  15.     Window handling functions.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21.  
  22. ***/
  23.  
  24. #include "xvi.h"
  25.  
  26. #undef    min
  27. #define    min(a, b)    (((a) < (b)) ? (a) : (b))
  28.  
  29. static    int    nwindows = 0;
  30.  
  31. static    Xviwin    *new_window P((Xviwin *, Xviwin *));
  32. static    bool_t    setup_window P((Xviwin *));
  33.  
  34. Xviwin *
  35. init_window(vs)
  36. VirtScr    *vs;
  37. {
  38.     Xviwin    *newwin;
  39.     newwin = new_window((Xviwin *) NULL, (Xviwin *) NULL);
  40.     if (newwin == NULL) {
  41.     return(NULL);
  42.     }
  43.  
  44.     newwin->w_vs = vs;
  45.     newwin->w_nrows = (*vs->v_rows)(vs);
  46.     newwin->w_ncols = (*vs->v_cols)(vs);
  47.  
  48.     /*
  49.      * Initialise screen stuff.
  50.      */
  51.     init_screen(newwin);
  52.  
  53.     newwin->w_winpos = 0;
  54.     newwin->w_cmdline = Rows - 1;
  55.     return(newwin);
  56. }
  57.  
  58. /*
  59.  * Split the given window in half, placing a new empty
  60.  * window in the bottom section and resizing the old one
  61.  * in the top half.
  62.  */
  63. Xviwin *
  64. split_window(oldwin)
  65. Xviwin    *oldwin;
  66. {
  67.     Xviwin    *newwin;
  68.  
  69.     /*
  70.      * Make sure there are enough rows for the new window.
  71.      * This does not obey the minrows parameter, because
  72.      * the point is to have enough space to actually display
  73.      * a window, not just to have a zero-size one.
  74.      */
  75.     if (oldwin->w_nrows < (MINROWS * 2))
  76.     return(NULL);
  77.  
  78.     newwin = new_window(oldwin, oldwin->w_next);
  79.     if (newwin == NULL) {
  80.     return(NULL);
  81.     }
  82.  
  83.     newwin->w_vs = oldwin->w_vs;
  84.  
  85.     /*
  86.      * Calculate size and position of new and old windows.
  87.      */
  88.     newwin->w_nrows = oldwin->w_nrows / 2;
  89.     newwin->w_cmdline = oldwin->w_cmdline;
  90.     newwin->w_winpos = (newwin->w_cmdline - newwin->w_nrows) + 1;
  91.  
  92.     oldwin->w_nrows -= newwin->w_nrows;
  93.     oldwin->w_cmdline = newwin->w_winpos - 1;
  94.  
  95.     newwin->w_ncols = oldwin->w_ncols;
  96.  
  97.     return(newwin);
  98. }
  99.  
  100. /*
  101.  * Delete the given window.
  102.  */
  103. void
  104. free_window(window)
  105. Xviwin    *window;
  106. {
  107.     if (window == NULL || nwindows < 1)
  108.     return;
  109.  
  110.     if (window->w_next != NULL) {
  111.     window->w_next->w_last = window->w_last;
  112.     }
  113.     if (window->w_last != NULL) {
  114.     window->w_last->w_next = window->w_next;
  115.     }
  116.     nwindows -= 1;
  117.  
  118.     window->w_buffer->b_nwindows -= 1;
  119.  
  120.     free((char *) window->w_cursor);
  121.     flexdelete(&window->w_statusline);
  122.     free((char *) window);
  123. }
  124.  
  125. /*
  126.  * Allocate a new window.
  127.  */
  128. static Xviwin *
  129. new_window(last, next)
  130. Xviwin    *last, *next;
  131. {
  132.     Xviwin    *newwin;
  133.  
  134.     newwin = (Xviwin *) malloc(sizeof(Xviwin));
  135.     if (newwin == NULL) {
  136.     return(NULL);
  137.     }
  138.  
  139.     if (setup_window(newwin) == FALSE) {
  140.     free((char *) newwin);
  141.     return(NULL);
  142.     }
  143.  
  144.     /*
  145.      * Link the window into the list.
  146.      */
  147.     if (last != NULL) {
  148.     last->w_next = newwin;
  149.     }
  150.     if (next != NULL) {
  151.     next->w_last = newwin;
  152.     }
  153.     newwin->w_last = last;
  154.     newwin->w_next = next;
  155.     nwindows += 1;
  156.  
  157.     return(newwin);
  158. }
  159.  
  160. /*
  161.  * Set up and allocate data structures for the given window,
  162.  * assumed to contain a valid pointer to a buffer.
  163.  *
  164.  * This routine should be called after setup_buffer().
  165.  */
  166. static bool_t
  167. setup_window(w)
  168. Xviwin    *w;
  169. {
  170.     /*
  171.      * Allocate space for the status line.
  172.      */
  173.     flexnew(&w->w_statusline);
  174.  
  175.     /*
  176.      * Allocate a Posn structure for the cursor.
  177.      */
  178.     w->w_cursor = (Posn *) malloc(sizeof(Posn));
  179.     if (w->w_cursor == NULL) {
  180.     return(FALSE);
  181.     }
  182.  
  183.     return(TRUE);
  184. }
  185.  
  186. void
  187. map_window_onto_buffer(w, b)
  188. Xviwin    *w;
  189. Buffer    *b;
  190. {
  191.     /*
  192.      * Connect the two together.
  193.      */
  194.     w->w_buffer = b;
  195.     b->b_nwindows += 1;
  196.  
  197.     /*
  198.      * Put the cursor and the screen in the right place.
  199.      */
  200.     move_cursor(w, b->b_file, 0);
  201.     w->w_topline = b->b_file;
  202.     w->w_botline = b->b_lastline;
  203.  
  204.     /*
  205.      * Miscellany.
  206.      */
  207.     w->w_row = w->w_col = 0;
  208.     w->w_virtcol = 0;
  209.     w->w_curswant = 0;
  210.     w->w_set_want_col = FALSE;
  211.     w->w_curs_new = TRUE;
  212. }
  213.  
  214. /*
  215.  * Unmap the given window from its buffer.
  216.  * We don't need to do much here, on the assumption that the
  217.  * calling code is going to do a map_window_onto_buffer()
  218.  * immediately afterwards; the vital thing is to decrement
  219.  * the window reference count.
  220.  */
  221. void
  222. unmap_window(w)
  223. Xviwin    *w;
  224. {
  225.     w->w_buffer->b_nwindows -= 1;
  226.  
  227.     w->w_cursor->p_line = NULL;
  228.     w->w_topline = NULL;
  229.     w->w_botline = NULL;
  230. }
  231.  
  232. /*
  233.  * Given a window, find the "next" one in the list.
  234.  */
  235. Xviwin *
  236. next_window(window)
  237. Xviwin    *window;
  238. {
  239.     if (window == NULL) {
  240.     return(NULL);
  241.     } else if (window->w_next != NULL) {
  242.     return(window->w_next);
  243.     } else {
  244.     Xviwin    *tmp;
  245.  
  246.     /*
  247.      * No next window; go to start of list.
  248.      */
  249.     for (tmp = window; tmp->w_last != NULL; tmp = tmp->w_last)
  250.         ;
  251.     return(tmp);
  252.     }
  253. }
  254.  
  255. /*
  256.  * Find the next window onto the buffer with the given filename,
  257.  * starting at the current one; if there isn't one, or if it is
  258.  * too small to move into, return NULL.
  259.  */
  260. Xviwin *
  261. find_window(window, filename)
  262. Xviwin    *window;
  263. char    *filename;
  264. {
  265.     Xviwin    *wp;
  266.     char    *f;
  267.  
  268.     if (window != NULL && filename != NULL) {
  269.     wp = window;
  270.     do {
  271.         f = wp->w_buffer->b_filename;
  272.         if (f != NULL && strcmp(filename, f) == 0) {
  273.         return(wp);
  274.         }
  275.         wp = next_window(wp);
  276.     } while (wp != window);
  277.     }
  278.  
  279.     return(NULL);
  280. }
  281.  
  282. /*
  283.  * Grow or shrink the given buffer window by "nlines" lines.
  284.  * We prefer to move the bottom of the window, and will only
  285.  * move the top when there is no room for manoeuvre below
  286.  * the current one - i.e. any windows are at minimum size.
  287.  */
  288. void
  289. resize_window(window, nlines)
  290. Xviwin    *window;
  291. int    nlines;
  292. {
  293.     unsigned    savecho;
  294.  
  295.     if (nlines == 0 || nwindows == 1) {
  296.     /*
  297.      * Nothing to do.
  298.      */
  299.     return;
  300.     }
  301.  
  302.     savecho = echo;
  303.  
  304.     if (nlines < 0) {
  305.     int    spare;        /* num spare lines in this window */
  306.  
  307.     nlines = - nlines;
  308.  
  309.     /*
  310.      * The current window must always contain 2 rows,
  311.      * so that the cursor has somewhere to go.
  312.      */
  313.     spare = window->w_nrows - MINROWS;
  314.  
  315.     /*
  316.      * If the window is already as small as it
  317.      * can get, don't bother to do anything.
  318.      */
  319.     if (spare <= 0)
  320.         return;
  321.  
  322.     /*
  323.      * Don't allow any screen updating until we've
  324.      * finished moving things around.
  325.      */
  326.     echo &= ~e_CHARUPDATE;
  327.  
  328.     /*
  329.      * First shrink the current window up from the bottom.
  330.      *
  331.      * move_sline()'s return value should be negative or 0
  332.      * in this case.
  333.      */
  334.     nlines += move_sline(window, - min(spare, nlines));
  335.  
  336.     /*
  337.      * If that wasn't enough, grow the window above us
  338.      * by the appropriate number of lines.
  339.      */
  340.     if (nlines > 0) {
  341.         (void) move_sline(window->w_last, nlines);
  342.     }
  343.     } else {
  344.     /*
  345.      * Don't allow any screen updating until we've
  346.      * finished moving things around.
  347.      */
  348.     echo &= ~e_CHARUPDATE;
  349.  
  350.     /*
  351.      * Expand window.
  352.      */
  353.     nlines -= move_sline(window, nlines);
  354.     if (nlines > 0) {
  355.         (void) move_sline(window->w_last, -nlines);
  356.     }
  357.     }
  358.  
  359.     /*
  360.      * Update screen. Note that status lines have
  361.      * already been updated by move_sline().
  362.      *
  363.      * This still needs a lot more optimization.
  364.      */
  365.     echo = savecho;
  366.     update_all();
  367. }
  368.  
  369. /*
  370.  * Adjust the boundary between two adjacent windows by moving the status line
  371.  * up or down, updating parameters for both windows as appropriate.
  372.  *
  373.  * Note that this can shrink the window to size 0.
  374.  */
  375. int
  376. move_sline(wp, nlines)
  377. Xviwin    *wp;        /* window whose status line we have to move */
  378. int    nlines;        /*
  379.              * number of lines to move (negative for
  380.              * upward moves, positive for downwards)
  381.              */
  382. {
  383.     Xviwin    *nextwin;
  384.  
  385.     if (wp == NULL || (nextwin = wp->w_next) == NULL) {
  386.     return(0);
  387.     }
  388.  
  389.     if (nlines < 0) {        /* move upwards */
  390.     int    amount;
  391.     int    spare;
  392.  
  393.     amount = -nlines;
  394.     spare = wp->w_nrows - Pn(P_minrows);
  395.  
  396.     if (amount > spare && wp->w_last != NULL) {
  397.         /*
  398.          * Not enough space: call move_sline() recursively
  399.          * for previous line; note that the second parameter
  400.          * should be negative.
  401.          */
  402.         (void) move_sline(wp->w_last, spare - amount);
  403.         spare = wp->w_nrows - Pn(P_minrows);
  404.     }
  405.     if (amount > spare)
  406.         amount = spare;
  407.     if (amount != 0) {
  408.         wp->w_nrows -= amount;
  409.         wp->w_cmdline -= amount;
  410.         nextwin->w_winpos -= amount;
  411.         nextwin->w_nrows += amount;
  412.         (void) shiftdown(nextwin, (unsigned) amount);
  413.         if (wp->w_nrows > 0) {
  414.         show_file_info(wp);
  415.         }
  416.     }
  417.     nlines = -amount;    /* return value */
  418.     } else {            /* move downwards */
  419.     int    spare;
  420.  
  421.     spare = nextwin->w_nrows - Pn(P_minrows);
  422.  
  423.     if (nlines > spare) {
  424.         /*
  425.          * Not enough space: call move_sline()
  426.          * recursively for next line.
  427.          */
  428.         (void) move_sline(nextwin, nlines - spare);
  429.         spare = nextwin->w_nrows - Pn(P_minrows);
  430.     }
  431.     if (nlines > spare)
  432.         nlines = spare;
  433.     if (nlines != 0) {
  434.         wp->w_nrows += nlines;
  435.         wp->w_cmdline += nlines;
  436.         nextwin->w_winpos += nlines;
  437.         nextwin->w_nrows -= nlines;
  438.         (void) shiftup(nextwin, (unsigned) nlines);
  439.         if (wp->w_nrows > 0) {
  440.         show_file_info(wp);
  441.         }
  442.     }
  443.     }
  444.     return(nlines);
  445. }
  446.  
  447. /*
  448.  * Update all windows associated with the given buffer.
  449.  */
  450. void
  451. update_buffer(buffer)
  452. Buffer    *buffer;
  453. {
  454.     Xviwin    *w;
  455.         
  456.     w = curwin;        /* as good a place as any to start */
  457.     do {
  458.     if (w->w_buffer == buffer) {
  459.         update_window(w);
  460.     }
  461.     w = next_window(w);
  462.     } while (w != curwin);
  463. }
  464.  
  465. bool_t
  466. can_split()
  467. {
  468.     return(nwindows < Pn(P_autosplit));
  469. }
  470.